using System;
using System.Collections.Generic;
using System.Text;
using Technoera.Common.Infrastructure;
using NHibernate;

namespace Technoera.Common.Nh
{
    public class NhPersistenceContext : IPersistenceContext
    {
        private NhManager _nhManager;
        private ISession _session;
        private ITransaction _currentTransaction;
        private bool disposed = false;
        
        public NhPersistenceContext(NhManager nhManager)
        {
            _nhManager = nhManager;
            _session = nhManager.GetNewSession();
        }

        ~NhPersistenceContext()
        {
            this.Dispose();
        }

        public ISession Session
        {
            get
            {
                if (_session == null)
                {
                    if (disposed)
                    {
                        throw new NhPersistenceContextException(Properties.Resources.ThePersistenceContextWasDisposed);
                    }
                    else
                    {
                        _session = _nhManager.GetNewSession();
                    }
                }

                return _session;
            }
        }

        public void BeginTransaction()
        {
            if (_currentTransaction != null && _currentTransaction.IsActive)
            {
                throw new NhPersistenceContextException(Properties.Resources.ThereIsAlreadyAnActiveTransaction);
            }
            
            _currentTransaction = this.Session.BeginTransaction();
        }

        public void CommitTransaction()
        {
            if (_currentTransaction == null)
            {
                throw new NhPersistenceContextException(Properties.Resources.ThereIsntAnActiveTransaction);
            }

            _currentTransaction.Commit();

            _currentTransaction.Dispose();
            _currentTransaction = null;
        }

        public void RollbackTransaction()
        {
            if (_currentTransaction == null)
            {
                throw new NhPersistenceContextException(Properties.Resources.ThereIsntAnActiveTransaction);
            }

            _currentTransaction.Rollback();

            _currentTransaction.Dispose();
            _currentTransaction = null;
        }

        public bool HasActiveTransaction
        {
            get
            {
                if (disposed)
                {
                    throw new NhPersistenceContextException(Properties.Resources.ThePersistenceContextWasDisposed);
                }
                else
                {
                    return (_currentTransaction != null && _currentTransaction.IsActive);
                }
            }
        }

        public void Attach(object entity)
        {
            this.Session.Lock(entity, LockMode.Read);
        }

        public void Dispose()
        {
            if (_session != null)
            {
                try
                {
                    if (_session.IsOpen)
                    {
                        if (_currentTransaction != null)
                        {
                            if (_currentTransaction.IsActive)
                            {
                                _currentTransaction.Rollback();
                            }
                            _currentTransaction.Dispose();
                            _currentTransaction = null;
                        }
                        _session.Close();
                    }
                    _session.Dispose();
                    _session = null;
                }
                catch { }
            }
            disposed = true;
            GC.SuppressFinalize(this);
        }

        public bool IsUninitializedProxy(object proxy)
        {
            return !NHibernateUtil.IsInitialized(proxy);
        }

        public void TryRollbackTransaction()
        {
            try
            {
                RollbackTransaction();
            }
            catch
            {
            }
        }
    }
}
